package cn.kerui.auth.controller;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.kerui.auth.mapper.AuthTokenExtMapper;
import cn.kerui.auth.service.IAuthStrategy;
import cn.kerui.auth.service.LoginService;
import cn.kerui.auth.vo.CaptchaVo;
import cn.kerui.auth.vo.LoginBody;
import cn.kerui.auth.vo.LoginVo;
import cn.kerui.common.annotation.SecurityRequest;
import cn.kerui.common.captcha.enums.CaptchaTypeEnum;
import cn.kerui.common.captcha.properties.CaptchaProperties;
import cn.kerui.common.core.domain.CommonResult;
import cn.kerui.common.framework.util.lang.StringUtil;
import cn.kerui.common.framework.util.spring.util.SpringContextUtil;
import cn.kerui.common.log.mvc.annotation.LoggerAdvice;
import cn.kerui.common.redis.constants.AuthRedisConstants;
import cn.kerui.common.redis.helper.RedisHelper;
import com.alibaba.fastjson.JSON;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p> 认证相关控制层 </p>
 * <p>创建于 2023/12/14 19:58 </p>
 *
 * @author yangkai
 * @version v1.0
 * @since 1.0.0
 */
@RestController
@RequestMapping("/auth")
@Slf4j
//@AllArgsConstructor
@LoggerAdvice
public class AuthController {

    @Autowired
    private AuthTokenExtMapper authTokenExtMapper;

    @Autowired
    private CaptchaProperties captchaProperties;

    @Autowired
    private RedisHelper redisHelper;

    @Autowired
    private LoginService loginService;

    /**
     * 获取验证码
     */
    @PostMapping("/code")
    @LoggerAdvice
    public CommonResult<CaptchaVo> captchaAuthCode() {
        CaptchaVo captchaVo = new CaptchaVo();
        if (!captchaProperties.getEnable()) {
            log.info("未配置开启验证码生成, 不生成图片验证码");
            captchaVo.setCaptchaEnabled(false);
            return CommonResult.okResult(captchaVo);
        }
        // 保存验证码信息
        String uuid = IdUtil.simpleUUID();

        // 获取验证码类型 （暂时只实现了math, char）
        CaptchaTypeEnum type = captchaProperties.getType();

        boolean isMath = CaptchaTypeEnum.MATH == type;
        Integer maxLength = isMath ? captchaProperties.getMathLength() : captchaProperties.getCharLength();
        CodeGenerator codeGenerator = ReflectUtil.newInstance(type.getClazz(), maxLength);
        AbstractCaptcha abstractCaptcha = SpringContextUtil.getBean(captchaProperties.getCaptchaCategory().getClazz());

        abstractCaptcha.setGenerator(codeGenerator);
        abstractCaptcha.createCode();
        String code = abstractCaptcha.getCode();
        if (isMath) {
            ExpressionParser parser = new SpelExpressionParser();
            Expression exp = parser.parseExpression(StringUtil.removeAny(code, "="));
            code = exp.getValue(String.class);
        }
        redisHelper.setObj(AuthRedisConstants.CAPTCHA_KEY, uuid, code, 60);
        captchaVo.setUuid(uuid);
        captchaVo.setImage(abstractCaptcha.getImageBase64());

        return CommonResult.okResult(captchaVo);
    }

    /**
     * 用户登录
     */
    @SecurityRequest
    @PostMapping("/login")
    public LoginVo login(@Valid @RequestBody LoginBody loginBody) {
        String grantType = loginBody.getGrantType();
        // 查询配置的token配置项
        SaLoginModel loginModel = authTokenExtMapper.getLoginModel(loginBody.getUserTerminal().getSerializableValue());
        LoginVo login = IAuthStrategy.login(JSON.toJSONString(loginBody), grantType, loginModel);

        // TODO 发布事件，提示用户登录成功
        return login;
    }

    @PostMapping("/logout")
    public void logout() {
        loginService.logout();
    }

    /**
     * 校验用户是否登录
     * @return
     */
    @PostMapping("/isLogin")
    public CommonResult isLogin() {
        StpUtil.checkLogin();
        boolean login = StpUtil.isLogin();
//        // 查看当前用户以及当前设备类型是否登录
//        String pc = StpUtil.getTokenValueByLoginId(65);
//        log.info("当前已经存在登录状态， token = {}", pc);
//        StpUtil.logout();
//        StpUtil.logoutByTokenValue(pc);
        return CommonResult.okResult(login);
    }
}
